<?php

namespace app\common\model\banxi\organization;

use app\common\enums\LevelTypeEnum;
use app\common\enums\organization\OrganizationUpTypeEnum;
use app\common\enums\OrganizationStateEnum;
use app\common\model\banxi\core\CoreAccountClassHour;
use app\common\model\common\BaseModel;
use think\db\exception\PDOException;
use think\Exception;
use think\exception\ValidateException;
use think\Model;
use think\model\concern\SoftDelete;

/**
 * 机构
 */
class Organization extends BaseModel
{
    use SoftDelete;

    protected $name = 'banxi_organization';

    protected $autoWriteTimestamp = true;

    protected $deleteTime = 'del';

    protected $defaultSoftDelete = 0;

    protected $append = [
        'statusCn',
        'areas'
    ];
    protected $type = [
        'id' => 'string',
        'del' => 'string',
        'level' => 'string',
        'isCompanionRunReward' => 'boolean',
        'createTime' => 'timestamp:Y-m-d H:i:s',
        'updateTime' => 'timestamp:Y-m-d H:i:s',
    ];
    private $organizationInfo = [
        "id" => "0",
        "name" => "总平台",
        "managerName" => ""
    ];

    //-----------------------------------------------------------------------------------
    //-                                    获取器                                      -
    //-----------------------------------------------------------------------------------

    public function getStatusCnAttr($value, $data)
    {
        $value = $value ?: ($data['status'] ?? '');
        return (new OrganizationStateEnum())->getDescription($value) ?? '';
    }

    public function getAreasAttr($value, $data)
    {
        $value = $value ?: ($data['area'] ?? '');
        return $value ? explode(',', $value) : [];
    }

    //-----------------------------------------------------------------------------------
    //-                                    处理方法                                      -
    //-----------------------------------------------------------------------------------


    public function getOrganizationInfo(): array
    {
        return $this->organizationInfo;
    }

    public function getListPage(array $where, string $page = '1', int $limit = 10)
    {
        return $this->with([
            'organizationBaseInfo' => function ($query) {
                $query->field('id,name,managerName');
            },
            'inviteInfo' => function ($query) {
                $query->field('id,name,managerName');
            },
            'accompanyInfo' => function ($query) {
                $query->field('id,name,managerName');
            },
            "accountClassHour",
            'organizationUser',
            'levelInfo'
        ])->where($where)
            ->order(['id' => 'desc'])
            ->paginate([
                'page' => $page,
                'list_rows' => $limit,
            ])->each(function ($item) {
                if ($item['parentId'] == 0) {
                    $item['organizationBaseInfo'] = $this->getOrganizationInfo();
                }
            });
    }

    public function getListSelectPage(array $where, string $page = '1', int $limit = 10)
    {
        $list = $this->where($where)
            ->field('id,name')
            ->order(['id' => 'desc'])
            ->paginate([
                'page' => $page,
                'list_rows' => $limit,
            ]);
        $list = result_row($list);
        $list['total'] += 1;
        array_unshift($list['rows'], $this->getOrganizationInfo());
        return $list;
    }

    public function getListLevelSelectPage(array $data, string $page = "1", int $limit = 10)
    {
        $where = [
            ['o.status', '<>', OrganizationStateEnum::E1]
        ];
        $query = $data['query'];
        if (isset($query['ids'])) {
            $where[] = ['o.id', 'in', $query['ids']];
        }
        if (isset($query['levelType'])) {
            $where[] = ['lc.levelType', '=', $query['levelType']];
        }
        if (!empty($data['searchText'])) {
            $where[] = ['o.name', 'like', '%' . $data['searchText'] . '%'];
        }
        $list = $this->alias('o')
            ->join('banxi_organization_level_config lc', 'lc.id = o.level')
            ->where($where)
            ->order(['o.id' => 'desc'])
            ->field('o.id,o.name,o.managerName,o.level,lc.levelType')
            ->paginate([
                'page' => $page,
                'list_rows' => $limit
            ]);
        $list = result_row($list);
        $list['total'] += 1;
        $organizationModel = new Organization();
        array_unshift($list['rows'], $organizationModel->getOrganizationInfo());
        return $list;
    }


    public function getInfo(array $where): array|Model|null
    {
        $info = $this->with([
            'organizationBaseInfo' => function ($query) {
                $query->field('id,name,managerName');
            },
            'inviteInfo' => function ($query) {
                $query->field('id,name,managerName');
            },
            'accompanyInfo' => function ($query) {
                $query->field('id,name,managerName');
            },
            "accountClassHour",
            'organizationUser',
            'levelInfo'
        ])->where($where)->find();
        if (empty($info)) {
            return [];
        }
        if ($info['parentId'] == 0) {
            $info['organizationBaseInfo'] = $this->getOrganizationInfo();
        }
        return $info;
    }

    public function saveOrUpdate(array $data, string|int $organizationId = null): bool
    {
        $this->startTrans();
        try {
            $saveData = $data;
            $id = $data['id'] ?? 0;
            $organizationInfo = $this->where('id', $id)->find();
            if (empty($organizationInfo)) {
                throw new ValidateException('操作失败,机构不存在');
            }
            if ($organizationId) {
                $sonOrganizationIds = $this->getSonOrganization($organizationId);
                if (!in_array($organizationInfo['parentId'], $sonOrganizationIds)) {
                    throw new ValidateException('操作失败,机构不存在');
                }
            }
            $newParentId = $data['parentId'] ?? 0;
            if ($id == $newParentId) {
                throw new ValidateException('操作失败,所属校区不能设置为自己');
            }

            $inviteId = $data['inviteId'] ?? '';
            if ($inviteId && $id == $inviteId) {
                throw new ValidateException('操作失败,自己不能邀请自己');
            }

            $accompanyId = $data['accompanyId'] ?? '';
            if ($accompanyId && $id == $accompanyId) {
                throw new ValidateException('操作失败,陪跑员不能设置为自己');
            }

            if (!empty($data['areas'])) {
                $saveData['area'] = implode(',', $data['areas']);
            }
            $openPhone = $data['openPhone'];
            $isExist = $this->where('openPhone', $openPhone)->where('id', '<>', $id)->count();
            if ($isExist) {
                throw new ValidateException('操作失败,开户人手机号已存在');
            }
            $organizationUser = OrganizationUser::where([
                'organizationId' => $id,
                'isAdmin' => 1
            ])->find();
            if (empty($organizationUser)){
                throw new ValidateException('操作失败,请先添加登录账户');
            }
            if (!empty($saveData['passwordUpdate'])) {
                $salt = createPasswordSalt();
                $organizationUser->salt = $salt;
                $organizationUser->password = createPassword($salt, $data['passwordUpdate']);
            }
            if ($data['openPhone'] != $organizationInfo['openPhone']) {
                $organizationUser->phone = $data['openPhone'];
            }
            $organizationUser->save();
            //修改所属校区
            $oldParentId = $organizationInfo['parentId'];
            $parentPath = $organizationInfo['parentPath'];
            if ($oldParentId != $newParentId) {
                if ($newParentId != 0) {
                    $parentOrganizationInfo = $this->where('id', $newParentId)->find();
                    if (!$parentOrganizationInfo) {
                        throw new ValidateException('操作失败,设置的校区不存在');
                    }
                    $parentPath = $parentOrganizationInfo['parentPath'] . ",{$newParentId}";
                } else {
                    $parentPath = "0";
                }
                $saveData['parentPath'] = $parentPath;
                $saveData['levelNum'] = substr_count($saveData['parentPath'], ',') + 1;
                // 批量更新子机构的parentPath和levelNum
                $list = $this->where('parentPath', 'like', "{$organizationInfo['parentPath']},%")->select();
                foreach ($list as $item) {
                    // 修正parentPath替换逻辑
                    $newParentPath = str_replace($organizationInfo['parentPath'], $parentPath, $item['parentPath']);
                    $item->save([
                        'parentPath' => $newParentPath,
                        'levelNum' => substr_count($newParentPath, ',') + 1
                    ]);
                }

            }
            //等级处理
            $oldLevel = $organizationInfo['level'];
            $newLevel = $data['level'];
            $organizationLevelConfigModel = new OrganizationLevelConfig();
            $levelConfigs = $organizationLevelConfigModel->where('id', 'in', [$newLevel, $oldLevel])->column('*', 'id');
            $newLevelInfo = $levelConfigs[$newLevel] ?? null;
            $oldLevelInfo = $levelConfigs[$oldLevel] ?? null;
            if (!$newLevelInfo) {
                throw new ValidateException('操作失败,设置的机构等级不存在');
            }
            if (!$oldLevelInfo) {
                throw new ValidateException('操作失败,原先设置的机构等级不存在');
            }
            if ($oldLevel != $newLevel) {
                $newLevelType = $newLevelInfo['levelType'] ?? null;
                $oldLevelType = $oldLevelInfo['levelType'] ?? null;
                if ($newLevelType != $oldLevelType) {
                    //合伙人=>超级校区
                    if ($oldLevelType == LevelTypeEnum::E2 && $newLevelType == LevelTypeEnum::E1) {
                        $this->where([
                            ['inviteId', '=', $id],
                            ['level', '>=', 4],
                        ])->select()->each(function ($item) use ($id, $parentPath) {
                            $newParentPath = "{$parentPath},{$id}";
                            $item->save([
                                'parentId' => $id,
                                'parentPath' => $newParentPath,
                                'levelNum' => substr_count($newParentPath, ',') + 1
                            ]);
                        });
                    }
                    //超级校区=>合伙人
                    if ($oldLevelType == LevelTypeEnum::E1 && $newLevelType == LevelTypeEnum::E2) {
                        throw new ValidateException('不允许超级校区变更为合伙人');
                    }
                }
                $organizationLevelRwModel = new OrganizationLevelRw();
                $beforeLevel = $oldLevelInfo['id'];
                $beforeLevelName = $oldLevelInfo['name'];
                $afterLevel = $newLevelInfo['id'];
                $afterLevelName = $newLevelInfo['name'];
                $organizationLevelRwModel->addUpLevelRw($id, $beforeLevel, $beforeLevelName, $afterLevel, $afterLevelName, OrganizationUpTypeEnum::E2);
            }

            $organizationInfo->save($saveData);
            $this->commit();
        } catch (ValidateException|PDOException|Exception $e) {
            $this->rollback();
            throw new ValidateException($e->getMessage());
        }
        return true;
    }

    public function updateEnable(string|int $id, string|int $organizationId = null)
    {
        $organizationInfo = $this->where('id', $id)->find();
        if (empty($organizationInfo)) {
            throw new ValidateException('操作失败，机构不存在');
        }
        if ($organizationId) {
            $sonOrganizationIds = $this->getSonOrganization($organizationId);
            if (!in_array($organizationInfo['parentId'], $sonOrganizationIds)) {
                throw new ValidateException('操作失败,机构不存在');
            }
        }
        if ($organizationInfo['status'] == 1) {
            throw new ValidateException('操作失败,机构不存在');
        }
        $statue = $organizationInfo->status == 2 ? 3 : 2;
        return $this->update(['status' => $statue], ['id' => $id]);
    }

    public function getOrganizationBaseInfo(string $organizationId): Organization|array|Model|null
    {
        if ($organizationId) {
            $organizationInfo = self::with([
                'levelInfo' => function ($query) {
                    $query->field('id,levelType,name');
                }])->where('id', $organizationId)->field('id,name,managerName,level')->find()->toArray();
        } else {
            $organizationInfo = $this->getOrganizationInfo();
        }
        return $organizationInfo;
    }

    /**
     * 获取机构下拉列表
     * @param string $organizationId
     * @param bool $isSelf 是否包含自己
     * @return array
     */
    public function getSonOrganization(string $organizationId): array
    {
        $organizationIds = $this->getJuniorOrganization($organizationId);
        $organizationIds[] = $organizationId;
        return $organizationIds;
    }

    /**
     * 获取机构下拉列表(包括自己)
     * @param string $organizationId
     * @return array
     */
    public function getJuniorOrganization(string $organizationId)
    {
        return self::where([['parentId', '=', $organizationId], ['status', '<>', OrganizationStateEnum::E1]])->order('id asc')->column('id');
    }

    //-----------------------------------------------------------------------------------
    //-                                    模型关联                                      -
    //-----------------------------------------------------------------------------------

    public function organizationBaseInfo()
    {
        return $this->hasOne(Organization::class, 'id', 'parentId');
    }

    public function inviteInfo()
    {
        return $this->hasOne(Organization::class, 'id', 'inviteId');
    }

    public function accompanyInfo()
    {
        return $this->hasOne(Organization::class, 'id', 'accompanyId');
    }

    public function organizationUser()
    {
        return $this->hasOne(OrganizationUser::class, 'organizationId', 'id');
    }


    public function levelInfo()
    {
        return $this->hasOne(OrganizationLevelConfig::class, 'id', 'level');
    }

    public function accountClassHour()
    {
        return $this->hasOne(CoreAccountClassHour::class, 'organizationId', 'id');
    }

}